using System;
using System.Linq;
using System.Text;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.ExpressApp.DC;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
using System.Collections.Generic;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using System.Security;
using DevExpress.Xpo.Metadata;
using DevExpress.ExpressApp.Security;
using System.Collections.ObjectModel;
using DevExpress.Persistent.Base.Security;

namespace DomainComponents.Common
{
    [DomainComponent]
    [XafDefaultProperty("DisplayName")]
    [VisibleInReports(false)]
    [ImageName("BO_User")]
    public interface IDCUser
    {
        string DisplayName { get; }
        string UserName { get; set; }
    }

    [DomainLogic(typeof(IDCUser))]
    public class DCUserLogic
    {
        public static string Get_DisplayName(IDCUser user)
        {
            return user.UserName;
        }
    }

    [DomainComponent]
    [ImageName("BO_User")]
    public interface IPersistentAuthenticationStandardUser : DevExpress.Persistent.Base.Security.IAuthenticationStandardUser, IDCUser
    {
        new bool ChangePasswordOnFirstLogon { get; set; }

        [System.ComponentModel.Browsable(false)]
        string StoredPassword { get; set; }
    }

    [DomainComponent]
    public interface IPersistentAuthenticationActiveDirectoryUser : IDCUser, DevExpress.Persistent.Base.Security.IAuthenticationActiveDirectoryUser
    {
    }

    [DomainComponent]
    [ImageName("BO_User")]
    public interface IPersistentSimpleSecurityUser : IDCUser, DevExpress.Persistent.Base.Security.ISimpleUser
    {
        [System.ComponentModel.DefaultValue(true)]
        new bool IsActive { get; set; }
        new bool IsAdministrator { get; set; }
    }

    [DomainComponent]
    [ImageName("BO_User")]
    public interface IPersistentComplexSecurityUser : DevExpress.Persistent.Base.Security.IUserWithRoles, IDCUser
    {
        [System.ComponentModel.DefaultValue(true)]
        new bool IsActive { get; set; }
        new IList<IPermission> Permissions { get; }
        [BackReferenceProperty("PersistentUsers")]
        IList<IPersistentRole> PersistentRoles { get; }
        [System.ComponentModel.Browsable(false)]
        new IList<DevExpress.Persistent.Base.Security.IRole> Roles { get; }
    }

    public class IPermissionToStringConverter : DevExpress.Xpo.Metadata.ValueConverter
    {
        public override object ConvertToStorageType(object value)
        {
            if (value != null && !(value is IPermission))
            {
                throw new ArgumentException(value.GetType().FullName);
            }
            if (value == null)
            {
                return null;
            }
            return ((IPermission)value).ToXml().ToString();
        }
        public override object ConvertFromStorageType(object value)
        {
            if (value != null && !(value is string))
            {
                throw new ArgumentException(value.GetType().FullName);
            }
            if (value == null || string.IsNullOrEmpty((string)value))
            {
                return null;
            }
            try
            {
                SecurityElement securityElement = SecurityElement.FromString((string)value);
                string typeName = securityElement.Attribute("class");
                string assemblyName = securityElement.Attribute("assembly");
                IPermission result = (IPermission)ReflectionHelper.CreateObject(typeName);
                result.FromXml(securityElement);
                return result;
            }
            catch (Exception e)
            {
                Tracing.Tracer.LogError(e);
            }
            return null;
        }
        public override Type StorageType
        {
            get { return typeof(string); }
        }
    }

    public class TypeToStringConverter : ValueConverter
    {
        public override object ConvertFromStorageType(object stringObjectType)
        {
            return ReflectionHelper.FindType((string)stringObjectType);
        }
        public override object ConvertToStorageType(object objectType)
        {
            if (objectType == null)
            {
                return null;
            }
            return ((Type)objectType).FullName;
        }
        public override Type StorageType
        {
            get { return typeof(string); }
        }
    }

    [DomainComponent]
    public interface IObjectAccessPermission
    {
        [ValueConverter(typeof(TypeToStringConverter))]
        [Size(512)]
        [TypeConverter(typeof(PermissionTargetBusinessClassListConverter))]
        Type TargetObjectType { get; set; }

        ObjectAccessModifier CreateAccess { get; set; }
        ObjectAccessModifier DeleteAccess { get; set; }
        ObjectAccessModifier ReadAccess { get; set; }
        ObjectAccessModifier WriteAccess { get; set; }
        ObjectAccessModifier NavigateAccess { get; set; }
    }

    [DomainComponent]
    [VisibleInReports(false)]
    [ImageName("BO_Role")]
    public interface IPersistentRole : DevExpress.Persistent.Base.Security.IRole
    {
        new string Name { get; set; }
        bool CanEditModel { get; set; }
        [BackReferenceProperty("PersistentRoles")]
        IList<IPersistentComplexSecurityUser> PersistentUsers { get; }
        [System.ComponentModel.Browsable(false)]
        new IList<DevExpress.Persistent.Base.Security.IUser> Users { get; }
        [DevExpress.ExpressApp.DC.Aggregated]
        IList<IObjectAccessPermission> ObjectAccessPermissions { get; }
        [System.ComponentModel.Browsable(false)]
        new ReadOnlyCollection<IPermission> Permissions { get; }
        void AddPermission(Type objectType, ObjectAccess access);
        [CreateInstance]
        IObjectAccessPermission CreateObjectAccessPermission();
    }


    [DomainLogic(typeof(IPersistentAuthenticationStandardUser))]
    public class PersistentAuthenticationStandardUserUserLogic
    {
        public static bool ComparePassword(IPersistentAuthenticationStandardUser user, string password)
        {
            return UserImpl.ComparePassword(user.StoredPassword, password);
        }

        public static void SetPassword(IPersistentAuthenticationStandardUser user, string password)
        {
            user.StoredPassword = UserImpl.GeneratePassword(password);
        }
    }

    [DomainLogic(typeof(IPersistentComplexSecurityUser))]
    public class PersistentComplexSecurityUserLogic
    {
        public static void ReloadPermissions(IPersistentComplexSecurityUser user, IObjectSpace os)
        {
            os.ReloadCollection(user.PersistentRoles);
            foreach (IPersistentRole role in user.PersistentRoles)
            {
                os.ReloadObject(role);
                os.ReloadCollection(role.ObjectAccessPermissions);
                foreach (IObjectAccessPermission permission in role.ObjectAccessPermissions)
                {
                    os.ReloadObject(permission);
                }
            }
        }
        public static IList<IPermission> Get_Permissions(IPersistentComplexSecurityUser user)
        {
            return UserImpl.GetUserPermissions(user);
        }
        public static IList<DevExpress.Persistent.Base.Security.IRole> Get_Roles(IPersistentComplexSecurityUser user)
        {
            return new ListConverter<DevExpress.Persistent.Base.Security.IRole, IPersistentRole>(user.PersistentRoles);
        }
    }

    [DomainLogic(typeof(IPersistentRole))]
    public class PersistentRoleLogic
    {
        public static void AddPermission(IPersistentRole role, Type objectType, ObjectAccess access)
        {
            IObjectAccessPermission permission = role.CreateObjectAccessPermission();
            permission.TargetObjectType = objectType;
            if ((access & ObjectAccess.Read) == ObjectAccess.Read)
            {
                permission.ReadAccess = ObjectAccessModifier.Allow;
            }
            if ((access & ObjectAccess.Write) == ObjectAccess.Write)
            {
                permission.WriteAccess = ObjectAccessModifier.Allow;
            }
            if ((access & ObjectAccess.Create) == ObjectAccess.Create)
            {
                permission.CreateAccess = ObjectAccessModifier.Allow;
            }
            if ((access & ObjectAccess.Delete) == ObjectAccess.Delete)
            {
                permission.DeleteAccess = ObjectAccessModifier.Allow;
            }
            if ((access & ObjectAccess.Navigate) == ObjectAccess.Navigate)
            {
                permission.NavigateAccess = ObjectAccessModifier.Allow;
            }
            role.ObjectAccessPermissions.Add(permission);
        }
        public static IList<DevExpress.Persistent.Base.Security.IUser> Get_Users(IPersistentRole role)
        {
            return new ListConverter<DevExpress.Persistent.Base.Security.IUser, IPersistentComplexSecurityUser>(role.PersistentUsers);
        }
        public static ReadOnlyCollection<IPermission> Get_Permissions(IPersistentRole role)
        {
#if DebugTest
            List<IPermission> value;
            if(DEBUG_Permissions.TryGetValue(role, out value))
                return DEBUG_Permissions[role].AsReadOnly();
#endif
            List<IPermission> permissions = new List<IPermission>();
            EditModelPermission canEditModel = new EditModelPermission();
            canEditModel.Modifier = role.CanEditModel ? ModelAccessModifier.Allow : ModelAccessModifier.Deny;
            permissions.Add(canEditModel);

            foreach (IObjectAccessPermission persistentPermission in role.ObjectAccessPermissions)
            {
                ObjectAccessPermission permission = new ObjectAccessPermission();
                permission.ObjectType = persistentPermission.TargetObjectType;
                permission.CreateAccess = persistentPermission.CreateAccess;
                permission.ReadAccess = persistentPermission.ReadAccess;
                permission.WriteAccess = persistentPermission.WriteAccess;
                permission.NavigateAccess = persistentPermission.NavigateAccess;
                permission.DeleteAccess = persistentPermission.DeleteAccess;
                permissions.Add(permission);
            }
            return permissions.AsReadOnly();
        }
#if DebugTest
        public static Dictionary<IPersistentRole, List<IPermission>> DEBUG_Permissions = new Dictionary<IPersistentRole,List<IPermission>>();
#endif
    }

    //[DefaultClassOptions]
    ////[ImageName("BO_Contact")]
    ////[DefaultProperty("DisplayMemberNameForLookupEditorsOfThisType")]
    ////[DefaultListViewOptions(MasterDetailMode.ListViewOnly, false, NewItemRowPosition.None)]
    ////[Persistent("DatabaseTableName")]
    //// Specify more UI options using a declarative approach (http://documentation.devexpress.com/#Xaf/CustomDocument2701).
    //public class IUser : BaseObject
    //{ // Inherit from a different class to provide a custom primary key, concurrency and deletion behavior, etc. (http://documentation.devexpress.com/#Xaf/CustomDocument3146).
    //    public IUser(Session session)
    //        : base(session)
    //    {
    //    }
    //    public override void AfterConstruction()
    //    {
    //        base.AfterConstruction();
    //        // Place your initialization code here (http://documentation.devexpress.com/#Xaf/CustomDocument2834).
    //    }
    //    //private string _PersistentProperty;
    //    //[XafDisplayName("My display name"), ToolTip("My hint message")]
    //    //[ModelDefault("EditMask", "(000)-00"), Index(0), VisibleInListView(false)]
    //    //[Persistent("DatabaseColumnName"), RuleRequiredField(DefaultContexts.Save)]
    //    //public string PersistentProperty {
    //    //    get { return _PersistentProperty; }
    //    //    set { SetPropertyValue("PersistentProperty", ref _PersistentProperty, value); }
    //    //}

    //    //[Action(Caption = "My UI Action", ConfirmationMessage = "Are you sure?", ImageName = "Attention", AutoCommit = true)]
    //    //public void ActionMethod() {
    //    //    // Trigger a custom business logic for the current record in the UI (http://documentation.devexpress.com/#Xaf/CustomDocument2619).
    //    //    this.PersistentProperty = "Paid";
    //    //}
    //}
}
